home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / kernel.c < prev    next >
Encoding:
Text File  |  1994-08-10  |  12.6 KB  |  543 lines

  1. #undef    PROCLOG
  2.  
  3. /* Non pre-empting synchronization kernel, machine-independent portion */
  4. #if    defined(PROCLOG) || defined(PROCTRACE)
  5. #include <stdio.h>
  6. #endif
  7. #include <dos.h>
  8. #include <setjmp.h>
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "proc.h"
  12. #include "timer.h"
  13. #include "socket.h"
  14. #include "daemon.h"
  15. #include "hardware.h"
  16. #ifdef PROCLOG
  17. #include "files.h"
  18. #endif
  19.  
  20. #ifdef PROCLOG
  21. FILE *proclog;
  22. #endif
  23.  
  24. static int Stkchk = 1;
  25. struct proc *Curproc = NULLPROC;    /* Currently running process */
  26. struct proc *Rdytab = NULLPROC;        /* Processes ready to run (not including curproc) */
  27. struct proc *Waittab = NULLPROC;    /* Waiting process list */
  28. struct proc *Susptab = NULLPROC;    /* Suspended processes */
  29. static struct mbuf *Killq;
  30.  
  31. /*----------------------------------------------------------------------*
  32. * primitive semaphore operation to serialize resource access  (DK5DC)   *
  33. * semawait  waits for a semaphore to become free (0).                   *
  34. * If req is True, the semaphore will be incremented immediatly          *
  35. *                                                                       *
  36. * semrel will decrement the semaphore and set it to 0 if it becomes     *
  37. * negative                                                              *
  38. *-----------------------------------------------------------------------*/
  39.  
  40. void
  41. semwait(int *sema,int req)
  42. {
  43.    while(*sema > 0)
  44.       pwait(sema);
  45.    if (req)
  46.       *sema += 1;                       /* now lock it                  */
  47. }
  48.  
  49. void
  50. semrel(int *sema)
  51. {
  52.    if ((*sema -= 1) <= 0)
  53.       *sema = 0;
  54.    psignal(sema,0);                    /* signal to everbody who's waiting*/
  55.  
  56. }
  57.  
  58. /* Append proc entry to end of appropriate list */
  59. static void near
  60. addproc(struct proc *entry)            /* Pointer to entry */
  61. {
  62.     int i_state;
  63.     struct proc **head;
  64.  
  65.     if(entry == NULLPROC) {
  66.         return;
  67.     }
  68.     switch(entry->state){
  69.     case READY:
  70.         head = &Rdytab;
  71.         break;
  72.     case WAITING:
  73.         head = &Waittab;
  74.         break;
  75.     case SUSPEND:
  76.     case SUSPEND | WAITING:
  77.         head = &Susptab;
  78.         break;
  79.     }
  80.     i_state = dirps();
  81.  
  82.     entry->next = NULLPROC;
  83.  
  84.     if(*head == NULLPROC) {
  85.         /* Empty list, stick at beginning */
  86.         *head = entry;
  87.     } else {
  88.         struct proc *pp;
  89.  
  90.         /* Find last entry on list */
  91.         for(pp = *head; pp->next != NULLPROC; pp = pp->next)
  92.             ;
  93.         pp->next = entry;
  94.     }
  95.     restore(i_state);
  96. }
  97.  
  98. /* Remove a process entry from the appropriate table */
  99. static void near
  100. delproc(struct proc *entry)            /* Pointer to entry */
  101. {
  102.     int i_state;
  103.     struct proc *pp = NULLPROC, *pplast = NULLPROC, **head;
  104.  
  105.     if(entry == NULLPROC) {
  106.         return;
  107.     }
  108.     i_state = dirps();
  109.  
  110.     switch(entry->state) {
  111.     case READY:
  112.         head = &Rdytab;
  113.         break;
  114.     case WAITING:
  115.         head = &Waittab;
  116.         break;
  117.     case SUSPEND:
  118.     case SUSPEND|WAITING:
  119.         head = &Susptab;
  120.         break;
  121.     }
  122.  
  123.     for(pp = *head; pp != NULLPROC; pplast = pp, pp = pp->next) {
  124.         if(pp == entry) {
  125.             if(pplast != NULLPROC) {
  126.                 pplast->next = pp->next;
  127.             } else {
  128.                 *head = pp->next;
  129.             }
  130.             break;
  131.         }
  132.     }
  133.     restore(i_state);
  134. }
  135.  
  136. /* Create a process descriptor for the main function. Must be actually
  137.  * called from the main function!
  138.  * Note that standard I/O is NOT set up here.
  139.  */
  140. struct proc *
  141. mainproc(char *name)
  142. {
  143.     struct proc *pp;
  144.     /* Create process descriptor */
  145.     /* Don't call the xallocw functions! - DB3FL.920801 */
  146.     pp = mxalloc(sizeof(struct proc));
  147.  
  148.     /* Create name */
  149.     sprintf(pp->name,"%.16s",name);
  150.  
  151.     pp->stksize = 0;
  152.  
  153.     /* Make current */
  154.     pp->state = READY;
  155.     Curproc = pp;
  156.  
  157. #ifdef PROCLOG
  158.     proclog = fopen("\proclog",APPEND_TEXT);
  159. #endif
  160.  
  161.     return pp;
  162. }
  163.  
  164. /* Create a new, ready process and return pointer to descriptor.
  165.  * The general registers are not initialized, but optional args are pushed
  166.  * on the stack so they can be seen by a C function.
  167.  */
  168. struct proc *
  169. newproc(
  170. char *name,                /* Arbitrary user-assigned name string */
  171. unsigned int stksize,    /* Stack size in words to allocate */
  172. void (*pc)(),            /* Initial execution address */
  173. int iarg,                /* Integer argument (argc) */
  174. void *parg1,            /* Generic pointer argument #1 (argv) */
  175. void *parg2,            /* Generic pointer argument #2 (session ptr) */
  176. int freeargs)            /* if set, free args list on termination */
  177. {
  178.     struct proc *pp;
  179.     int i;
  180.  
  181.     if(Stkchk) {
  182.         chkstk();
  183.     }
  184.     /* Create process descriptor */
  185.     pp = mxallocw(sizeof(struct proc));
  186.  
  187.     /* Allocate stack */
  188.     pp->stack = cxallocw(sizeof(int16),stksize);
  189.     pp->stksize = stksize;
  190.  
  191.     /* Create name */
  192.     sprintf(pp->name,"%.16s",name);
  193.  
  194.     /* Initialize stack for high-water check */
  195.     for(i = 0; i < pp->stksize; i++) {
  196.         pp->stack[i] = STACKPAT;
  197.     }
  198.     /* Do machine-dependent initialization of stack */
  199.     psetup(pp,iarg,parg1,parg2,pc);
  200.  
  201.     pp->freeargs = freeargs;
  202.     pp->iarg = iarg;
  203.     pp->parg1 = parg1;
  204.     pp->parg2 = parg2;
  205.  
  206.     /* Inherit creator's input and output sockets */
  207.     usesock(Curproc->input);
  208.     pp->input = Curproc->input;
  209.     usesock(Curproc->output);
  210.     pp->output = Curproc->output;
  211.  
  212.     /* Add to ready process table */
  213.     pp->state = READY;
  214.     addproc(pp);
  215.     return pp;
  216. }
  217.  
  218. /* Free resources allocated to specified process. If a process wants to kill
  219.  * itself, the reaper is called to do the dirty work. This avoids some
  220.  * messy situations that would otherwise occur, like freeing your own stack.
  221.  */
  222. void
  223. killproc(struct proc *pp)
  224. {
  225.     char **argv;
  226. #ifdef PROCLOG
  227.     extern int stkutil __ARGS((struct proc *pp));
  228. #endif
  229.  
  230.     if(pp == NULLPROC)
  231.         return;
  232.  
  233.     /* Don't check the stack here!
  234.      * Will cause infinite recursion if called from a stack error.
  235.      */
  236.  
  237.     if(pp == Curproc)
  238.         killself();    /* Doesn't return */
  239.  
  240.     /* Close any open sockets */
  241.     freesock(pp);
  242.     close_s(pp->input);
  243.     close_s(pp->output);
  244.  
  245.     /* Stop alarm clock in case it's running */
  246.     stop_timer(&pp->alarm);
  247.  
  248.     /* Alert everyone waiting for this proc to die */
  249.     psignal(pp,0);
  250.  
  251.     /* Remove from appropriate table */
  252.     delproc(pp);
  253.  
  254. #ifdef PROCLOG
  255.     if(!uploadstatus) {
  256.         fprintf(proclog,"size %5u max %5u name %s\n",
  257.             pp->stksize,stkutil(pp),pp->name);
  258.         fflush(proclog);
  259.     }
  260. #endif
  261.  
  262.     /* Free allocated memory resources */
  263.     if(pp->freeargs){
  264.         argv = pp->parg1;
  265.         while(pp->iarg-- != 0)
  266.             xfree(*argv++);
  267.         xfree(pp->parg1);
  268.     }
  269.     xfree(pp->stack);
  270.     xfree(pp);
  271. }
  272.  
  273. /* Terminate current process by sending a request to the killer process.
  274.  * Automatically called when a process function returns. Does not return.
  275.  */
  276. void
  277. killself(void)
  278. {
  279.     if(Curproc != NULLPROC) {
  280.         struct mbuf *bp = pushdown(NULLBUF,sizeof(Curproc));
  281.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  282.         enqueue(&Killq,bp);
  283.     }
  284.  
  285.     /* "Wait for me; I will be merciful and quick." */
  286.     for(;;) {
  287.         pwait(NULL);
  288.     }
  289. }
  290.  
  291. /* Process used by processes that want to kill themselves */
  292. void
  293. killer(int i,void *v1,void *v2)
  294. {
  295.     struct proc *pp;
  296.     struct mbuf *bp;
  297.  
  298.     for(;;) {
  299.         while(Killq == NULLBUF) {
  300.             pwait(&Killq);
  301.         }
  302.         bp = dequeue(&Killq);
  303.         pullup(&bp,(char *)&pp,sizeof(pp));
  304.         free_p(bp);
  305.         if(pp != Curproc) {    /* We're immortal */
  306.             killproc(pp);
  307.         }
  308.     }
  309. }
  310.  
  311. /* Inhibit a process from running */
  312. void
  313. suspend(struct proc *pp)
  314. {
  315.     if(pp == NULLPROC)
  316.         return;
  317.  
  318.     if(pp != Curproc)
  319.         delproc(pp);    /* Running process isn't on any list */
  320.  
  321.     pp->state |= SUSPEND;
  322.  
  323.     if(pp != Curproc)
  324.         addproc(pp);    /* pwait will do it for us */
  325.     else
  326.         pwait(NULL);
  327. }
  328.  
  329. /* Restart suspended process */
  330. void
  331. resume(struct proc *pp)
  332. {
  333.     if(pp == NULLPROC)
  334.         return;
  335.  
  336.     delproc(pp);    /* Can't be Curproc! */
  337.     pp->state &= ~SUSPEND;
  338.     addproc(pp);
  339. }
  340.  
  341. /* Wakeup waiting process, regardless of event it's waiting for. The process
  342.  * will see a return value of "val" from its pwait() call.
  343.  */
  344. void
  345. alert(struct proc *pp,void *val)
  346. {
  347.     if(pp == NULLPROC)
  348.         return;
  349.  
  350. #ifdef    XXX
  351.     if((pp->state & WAITING) == 0)
  352.         return;
  353. #endif
  354.  
  355. #ifdef    PROCTRACE
  356.     tprintf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  357. #endif
  358.  
  359.     if(pp != Curproc)
  360.         delproc(pp);
  361.  
  362.     pp->state &= ~WAITING;
  363.     pp->retval = val;
  364.     pp->event = 0;
  365.  
  366.     if(pp != Curproc)
  367.         addproc(pp);
  368. }
  369.  
  370. /* Post a wait on a specified event and give up the CPU until it happens. The
  371.  * null event is special: it means "I don't want to block on an event, but let
  372.  * somebody else run for a while". It can also mean that the present process
  373.  * is terminating; in this case the wait never returns.
  374.  *
  375.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  376.  * arg in an alert() call. Pwait must not be called from interrupt level.
  377.  *
  378.  * Note that pwait can run with interrupts enabled even though it examines
  379.  * a few global variables that can be modified by psignal at interrupt time.
  380.  * These *seem* safe.
  381.  */
  382. void *
  383. pwait(void *event)
  384. {
  385.     struct proc *oldproc;
  386.     void *tmp;
  387.  
  388.     if(Curproc != NULLPROC) {    /* If process isn't terminating */
  389.         if(Stkchk)
  390.             chkstk();
  391.  
  392.         if(event == NULL) {
  393.             /* Special case; just give up the processor.
  394.              *
  395.              * Optimization: if nothing else is ready, just return.
  396.              */
  397.             if(Rdytab == NULLPROC) {
  398.                 return 0;
  399.             }
  400.         } else {
  401.             /* Post a wait for the specified event */
  402.             Curproc->event = event;
  403.             Curproc->state = WAITING;
  404.         }
  405.         addproc(Curproc);
  406.     }
  407.  
  408.     /* Look for a ready process and run it. If there are none,
  409.      * loop or halt until an interrupt makes something ready.
  410.      */
  411.     while(Rdytab == NULLPROC) {
  412.         /* Give system back to upper-level multitasker, if any.
  413.          * Note that this function enables interrupts internally
  414.          * to prevent deadlock, but it restores our state
  415.          * before returning.
  416.          */
  417.         giveup();
  418.     }
  419.  
  420.     /* Remove first entry from ready list */
  421.     oldproc = Curproc;
  422.     Curproc = Rdytab;
  423.     delproc(Curproc);
  424.  
  425.     /* Now do the context switch.
  426.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  427.      *
  428.      * If the old process has gone away, simply load the new process's
  429.      * environment. Otherwise, save the current process's state. Then if
  430.      * this is still the old process, load the new environment. Since the
  431.      * new task will "think" it's returning from the setjmp() with a return
  432.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  433.      * would otherwise cause an infinite loop.
  434.      */
  435. #ifdef    PROCTRACE
  436.     if(strcmp(oldproc->name,Curproc->name) != 0){
  437.         tprintf("-> %s(%d)\n",Curproc->name,!!Curproc->i_state);
  438.     }
  439. #endif
  440.     /* Note use of comma operator to save old interrupt state only if
  441.      * oldproc is non-null
  442.      */
  443.     if(oldproc == NULLPROC
  444.      || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)){
  445.         /* We're still running in the old task; load new task context.
  446.          * The interrupt state is restored here in case longjmp
  447.          * doesn't do it (e.g., systems other than Turbo-C).
  448.          */
  449.         restore(Curproc->i_state);
  450.         longjmp(Curproc->env,1);
  451.     }
  452.  
  453.     /* At this point, we're running in the newly dispatched task */
  454.     tmp = Curproc->retval;
  455.     Curproc->retval = 0;
  456.  
  457.     /* Also restore the true interrupt state here, in case the longjmp
  458.      * DOES restore the interrupt state saved at the time of the setjmp().
  459.      * This is the case with Turbo-C's setjmp/longjmp.
  460.      */
  461.     restore(Curproc->i_state);
  462.     return tmp;
  463. }
  464.  
  465. /* Make ready the first 'n' processes waiting for a given event. The ready
  466.  * processes will see a return value of 0 from pwait().  Note that they don't
  467.  * actually get control until we explicitly give up the CPU ourselves through
  468.  * a pwait(). Psignal may be called from interrupt level. It returns the
  469.  * number of processes that were woken up.
  470.  */
  471. int
  472. psignal(
  473. void *event,    /* Event to signal */
  474. int n)            /* Max number of processes to wake up */
  475. {
  476.     struct proc *pp;
  477.     int i_state;
  478.     int cnt = 0;                /* 0 means "signal everybody waiting" */
  479. //    if(Stkchk)
  480. // DL8YQ chkstk();
  481.  
  482.     if(event == NULL)
  483.         return 0;                /* Null events are invalid */
  484.  
  485.     if(n == 0)
  486.         n = 32766;
  487.  
  488.     i_state = dirps();
  489.  
  490.     for(pp = Waittab; pp != NULLPROC; pp = pp->next) {
  491.         if(n == 0)
  492.             break;
  493.  
  494.         if(pp->event == event){
  495. #ifdef    PROCTRACE
  496.             if(i_state){
  497.                 tprintf("psignal(%lx,%u) wake %lx [%s]\n",
  498.                     ptol(event),n,ptol(pp),pp->name);
  499.             }
  500. #endif
  501.             delproc(pp);
  502.             pp->state &= ~WAITING;
  503.             pp->event = 0;
  504.             pp->retval = 0;
  505.             addproc(pp);
  506.             n--;
  507.             cnt++;
  508.         }
  509.     }
  510.  
  511.     for(pp = Susptab; pp != NULLPROC; pp = pp->next) {
  512.         if(n == 0)
  513.             break;
  514.  
  515.         if(pp->event == event){
  516. #ifdef    PROCTRACE
  517.             if(i_state){
  518.                 tprintf("psignal(%lx,%u) wake %lx [%s]\n",
  519.                     ptol(event),n,ptol(pp),pp->name);
  520.             }
  521. #endif
  522.             delproc(pp);
  523.             pp->state &= ~WAITING;
  524.             pp->event = 0;
  525.             pp->retval = 0;
  526.             addproc(pp);
  527.             n--;
  528.             cnt++;
  529.         }
  530.     }
  531.     restore(i_state);
  532.     return cnt;
  533. }
  534.  
  535. // #ifdef XXX
  536. /* Rename a process */
  537. void
  538. chname(struct proc *pp,char *newname)
  539. {
  540.     sprintf(pp->name,"%.16s",newname);
  541. }
  542. // #endif
  543.